#include <ceres/ceres.h>

using ceres::CostFunction;
using ceres::Problem;
using ceres::SizedCostFunction;
using ceres::Solve;
using ceres::Solver;

// Minimize 0.5*(10-x)^2
//  1. using Jacobian matrix
//  2. computed using analytic differentiation
class QuatraticCostFunction : public SizedCostFunction<1 /* number of residuals */,
                                                       1 /* size of first parameter */>
{
public:
    virtual ~QuatraticCostFunction() {}

    virtual bool Evaluate(
        double const *const *parameters,
        double *residual,
        double **jacobian) const
    {
        double x = parameters[0][0];
        residual[0] = 10.0 - x; // derivative: f(x) = 10.0 - x

        if (jacobian != NULL && jacobian[0] != NULL)
        {
            jacobian[0][0] = -1; // f'(x) = -1
        }

        return true;
    }
};

int main()
{
    // the input variable
    double x = 0.5;
    const double initial_x = x;

    // the cost function known as residual
    CostFunction *cost_function = new QuatraticCostFunction;

    Problem problem;

    // use input and cost function to construct a problem
    problem.AddResidualBlock(cost_function, nullptr, &x);

    // options: parameters to control actions of the sovler
    // summary: save the intermediate result for the sovler
    Solver::Options options;
    options.minimizer_progress_to_stdout = true;
    Solver::Summary summary;

    Solve(options, &problem, &summary);

    std::cout << summary.BriefReport() << std::endl;
    std::cout << "x: " << initial_x << " -> " << x << std::endl;

    return 0;
}
